
#include "directorymanager.hpp"

/*########################################################################################################

  Funcions de la classe directoryManager
  
  La clase directoryManager s'encarrega de gestionar l'espai del disc.
  
  ######################################################################################################*/

directoryManager::directoryManager(char* disk)
{
    _buffman = new bufferManager (disk);
    _pagCtrl = _buffman -> query(0);
    
    // Mirem si hi ha contingut al disc
    byte b = _pagCtrl[0];
    if (b.getBit(0) == 0) {
        cout << "INFO: Disc nou." << endl;
        
        setUsedPag(0);
        newControl();
        cout << "INFO: S'ha creat l'espai de control. " << endl;
        
    } else {
        cout << "INFO: Disc amb contingut." << endl;
    }
}

directoryManager::~directoryManager()
{
    // Hem de guardar la memoria al disc!
    _buffman -> update(0);
}

// -------------------------------------------------------------------------------
// Funcions que gestionen les pagines del disc
// -------------------------------------------------------------------------------

int directoryManager::getFreePag()
{
    bool found = false;
    int i,x,n;
    
	for (i = 0; i < 512 && !found; i++)
	{
		byte val = _pagCtrl[i];
		
		// Revisem cada bit
		for (x = 0; x < 8 && !found; x++)
		{
		    n = i*8+x;
		    found = (val.getBit(x) == 0);
		}
	}
    
    return found ? n : -1;
}

void directoryManager::setFreePag(const int &n)
{
    _pagCtrl[n/8] &= ~(1 << n%8);
}

void directoryManager::setUsedPag(const int &n)
{
    _pagCtrl[n/8] |=  (1 << n%8);
}

bool directoryManager::isPagInUse(const int &n)
{
    byte val = _pagCtrl[n/8];
    return (val.getBit(n%8) != 0);
}

directoryManager::slot directoryManager::getSlot(const int &n)
{
    slot s;
    if (validSlot(n)) {
        unsigned char* bytes = (unsigned char *)&_pagCtrl[n];
        s.fileName = reinterpret_cast<char const*>(bytes);
        s.firstPag = readUShort(n+6, n+6+1);
        s.tipus =  (int) _pagCtrl[n+6+2] & 0XFF;
        
        
        //s.mr =  (unsigned short) _pagCtrl[n+6+3] & 0XFF;
        //s.mcc =  (unsigned short) _pagCtrl[n+6+4] & 0XFF;
        s.mr = readUShort(n+6+3, n+6+4);
        s.mcc = readUShort(n+6+5, n+6+6);
        
        s.slotNum = n;
    }
    return s;
}

directoryManager::slot directoryManager::getSlot(const string &fileName)
{
    slot ret;
    bool found = false;
    unsigned short sl;
    for (sl = 520; sl <= 1010 && !found; sl += 14) {
        slot s = getSlot(sl);
        if (s.fileName == fileName) {
            ret = s;
            found = true;
        }
    }
    return ret;
}

void directoryManager::setSlot(const slot &s)
{
    // Si estem dins del rang i el registre no s'ha utilitzat
    if (s.slotNum >= 520 && s.slotNum < 1024 && !validSlot(s.slotNum)) {
        unsigned char* bytes = (unsigned char *)&_pagCtrl[s.slotNum];

        // Escrivim el nom
        unsigned int i;
        for (i = 0; i < 6; i++){
            bytes[i] = s.fileName[i];
        }
        
        // Primera pagina
        writeUShort(s.firstPag, s.slotNum+6, s.slotNum+6+1);
        _pagCtrl[s.slotNum+6+2] = (char) ((s.tipus) & 0XFF);
        
        //_pagCtrl[s.slotNum+6+3] = (char) ((s.mr) & 0XFF);
        //_pagCtrl[s.slotNum+6+4] = (char) ((s.mcc) & 0XFF);
        writeUShort(s.mr, s.slotNum+6+3, s.slotNum+6+4);
        writeUShort(s.mcc, s.slotNum+6+5, s.slotNum+6+6);
        
    } else {
        cout <<  "ERROR SETSLOT( " << s.fileName << "): No s'ha pogut afegir el registre al disc." << endl;
    }
}

void directoryManager::updateSlot(const slot &s)
{
    unsigned char* bytes = (unsigned char *)&_pagCtrl[s.slotNum];

    // Escrivim el nom
    unsigned int i;
    for (i = 0; i < 6; i++){
        bytes[i] = s.fileName[i];
    }
    
    writeUShort(s.firstPag, s.slotNum+6, s.slotNum+6+1);
    _pagCtrl[s.slotNum+6+2] = (char) ((s.tipus) & 0XFF);
        
    //_pagCtrl[s.slotNum+6+3] = (char) ((s.mr) & 0XFF);
    //_pagCtrl[s.slotNum+6+4] = (char) ((s.mcc) & 0XFF);
    writeUShort(s.mr, s.slotNum+6+3, s.slotNum+6+4);
    writeUShort(s.mcc, s.slotNum+6+5, s.slotNum+6+6);
}

bool directoryManager::validSlot(const int &n)
{
    int i = 0;
    if (n >= 520 && n < 1024) {
        i = (int) _pagCtrl[n+6+2] & 0XFF;
    }
    return (i == 3);
}

void directoryManager::setNextPagVal(const int &currPag, const unsigned short &nextPag)
{
    char* pag = _buffman -> query(currPag);
	pag[0] = (char) ((nextPag>>8) & 0XFF);
	pag[1] = (char) ((nextPag) & 0XFF);
	_buffman -> update(currPag);
	//utils::mapArray (pag, 32, BIN);
}

unsigned short directoryManager::getNextPagVal(const int &currPag)
{
    char* pag = _buffman -> query(currPag);
    unsigned short i = (int) (pag[0] & 0XFF) << 8;
    i += (int) pag[1] & 0XFF;
    _buffman -> update(currPag);
    //utils::mapArray (pag, 32, BIN);
    return i;
}

// -------------------------------------------------------------------------------
// Funcions que gestionen els fitxers del disc
// -------------------------------------------------------------------------------

void directoryManager::newControl()
{
    writeUShort(520, 512, 513);
}

unsigned short directoryManager::getFreeSlot()
{
    unsigned short nfs = readUShort(512, 513);
    if (nfs < 1024)
        return nfs;
    else
        return 0;
}

void directoryManager::setFreeSlot(const int &n)
{
    writeUShort(n, 512, 513);
}

void directoryManager::deleteSlot(const int &n)
{
    int x, i;
    for (i = n; i < n + 6 + 7; i++)
    {
	    for (x = 0; x < 8; x++)
	        _pagCtrl[i] &= ~(1 << x);
    }
}

unsigned short directoryManager::readUShort(const int &pos1, const int &pos2)
{
    unsigned short i = (int) (_pagCtrl[pos1] & 0XFF) << 8;
    i += (int) _pagCtrl[pos2] & 0XFF;
    return i;
}

void directoryManager::writeUShort(const unsigned short &valor, const int &pos1, const int &pos2)
{
	_pagCtrl[pos1] = (char) ((valor>>8) & 0XFF);
	_pagCtrl[pos2] = (char) ((valor) & 0XFF);
}

